/* add user code begin Header */
/**
 **************************************************************************
 * @file     at32f415_wk_config.c
 * @brief    work bench config program
 **************************************************************************
 *                       Copyright notice & Disclaimer
 *
 * The software Board Support Package (BSP) that is made available to
 * download from Artery official website is the copyrighted work of Artery.
 * Artery authorizes customers to use, copy, and distribute the BSP
 * software and its related documentation for the purpose of design and
 * development in conjunction with Artery microcontrollers. Use of the
 * software is governed by this copyright notice and the following disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
 * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
 * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
 * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
 * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
 *
 **************************************************************************
 */
/* add user code end Header */

#include "at32f415_wk_config.h"

/* private includes ----------------------------------------------------------*/
/* add user code begin private includes */
#include "usb_conf.h"
#include "usb_core.h"
#include "usbd_int.h"
#include "cdc_class.h"
#include "cdc_desc.h"
/* add user code end private includes */

/* private typedef -----------------------------------------------------------*/
/* add user code begin private typedef */

/* add user code end private typedef */

/* private define ------------------------------------------------------------*/
/* add user code begin private define */

/* add user code end private define */

/* private macro -------------------------------------------------------------*/
/* add user code begin private macro */
extern otg_core_type otg_core_struct;
/* delay variable */
static __IO uint32_t fac_us;
static __IO uint32_t fac_ms;
#define STEP_DELAY_MS 50
/* add user code end private macro */

/* private variables ---------------------------------------------------------*/
/* add user code begin private variables */

/* add user code end private variables */

/* private function prototypes --------------------------------------------*/
/* add user code begin function prototypes */

/* add user code end function prototypes */

/* private user code ---------------------------------------------------------*/
/* add user code begin 0 */

/* add user code end 0 */

/**
 * @brief  system clock config program
 * @note   the system clock is configured as follow:
 *         system clock (sclk)   = hick / 12 * pll_mult
 *         system clock source   = HICK_VALUE
 *         - sclk                = 144000000
 *         - ahbdiv              = 1
 *         - ahbclk              = 144000000
 *         - apb1div             = 2
 *         - apb1clk             = 72000000
 *         - apb2div             = 2
 *         - apb2clk             = 72000000
 *         - pll_mult            = 36
 *         - flash_wtcyc         = 4 cycle
 * @param  none
 * @retval none
 */
void wk_system_clock_config(void)
{
    /* reset crm */
    crm_reset();

    /* config flash psr register */
    flash_psr_set(FLASH_WAIT_CYCLE_4);

    /* enable lick */
    crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);

    /* wait till lick is ready */
    while (crm_flag_get(CRM_LICK_STABLE_FLAG) != SET) {
    }

    /* enable hick */
    crm_clock_source_enable(CRM_CLOCK_SOURCE_HICK, TRUE);

    /* wait till hick is ready */
    while (crm_flag_get(CRM_HICK_STABLE_FLAG) != SET) {
    }

    /* config pll clock resource */
    crm_pll_config(CRM_PLL_SOURCE_HICK, CRM_PLL_MULT_36);

    /* enable pll */
    crm_clock_source_enable(CRM_CLOCK_SOURCE_PLL, TRUE);

    /* wait till pll is ready */
    while (crm_flag_get(CRM_PLL_STABLE_FLAG) != SET) {
    }

    /* config ahbclk */
    crm_ahb_div_set(CRM_AHB_DIV_1);

    /* config apb2clk, the maximum frequency of APB2 clock is 75 MHz  */
    crm_apb2_div_set(CRM_APB2_DIV_2);

    /* config apb1clk, the maximum frequency of APB1 clock is 75 MHz  */
    crm_apb1_div_set(CRM_APB1_DIV_2);

    /* enable auto step mode */
    crm_auto_step_mode_enable(TRUE);

    /* select pll as system clock source */
    crm_sysclk_switch(CRM_SCLK_PLL);

    /* wait till pll is used as system clock source */
    while (crm_sysclk_switch_status_get() != CRM_SCLK_PLL) {
    }

    /* disable auto step mode */
    crm_auto_step_mode_enable(FALSE);

    /* update system_core_clock global variable */
    system_core_clock_update();
}

/**
 * @brief  config periph clock
 * @param  none
 * @retval none
 */
void wk_periph_clock_config(void)
{
    /* enable usb_otgfs1 periph clock */
    crm_periph_clock_enable(CRM_OTGFS1_PERIPH_CLOCK, TRUE);

    /* enable iomux periph clock */
    crm_periph_clock_enable(CRM_IOMUX_PERIPH_CLOCK, TRUE);

    /* enable gpioa periph clock */
    crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);

    /* enable gpiob periph clock */
    crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);

    /* enable tmr1 periph clock */
    crm_periph_clock_enable(CRM_TMR1_PERIPH_CLOCK, TRUE);

    /* enable usart2 periph clock */
    crm_periph_clock_enable(CRM_USART2_PERIPH_CLOCK, TRUE);

    /* enable i2c1 periph clock */
    crm_periph_clock_enable(CRM_I2C1_PERIPH_CLOCK, TRUE);
}

/**
 * @brief  init debug function.
 * @param  none
 * @retval none
 */
void wk_debug_config(void)
{
    /* jtag-dp disabled and sw-dp enabled */
    gpio_pin_remap_config(SWJTAG_GMUX_010, TRUE);
}

/**
 * @brief  nvic config
 * @param  none
 * @retval none
 */
void wk_nvic_config(void)
{
    nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);

    nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
}

/**
 * @brief  init gpio_input/gpio_output/gpio_analog/eventout function.
 * @param  none
 * @retval none
 */
void wk_gpio_config(void)
{
    gpio_init_type gpio_init_struct;
    gpio_default_para_init(&gpio_init_struct);

    /* gpio input config */
    gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
    gpio_init_struct.gpio_pins = GPIO_PINS_15;
    gpio_init_struct.gpio_pull = GPIO_PULL_UP;
    gpio_init(GPIOA, &gpio_init_struct);

    /* gpio output config */
    gpio_bits_reset(GPIOA, GPIO_PINS_5);

    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode           = GPIO_MODE_OUTPUT;
    gpio_init_struct.gpio_pins           = GPIO_PINS_5;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);
}

/**
 * @brief  init i2c1 function.
 * @param  none
 * @retval none
 */
void wk_i2c1_init(void)
{
    /* add user code begin i2c1_init 0 */

    /* add user code end i2c1_init 0 */

    gpio_init_type gpio_init_struct;

    gpio_default_para_init(&gpio_init_struct);

    /* add user code begin i2c1_init 1 */

    /* add user code end i2c1_init 1 */

    /* configure the SCL pin */
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init_struct.gpio_pins           = GPIO_PINS_6;
    gpio_init(GPIOB, &gpio_init_struct);

    /* configure the SDA pin */
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_OPEN_DRAIN;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init_struct.gpio_pins           = GPIO_PINS_7;
    gpio_init(GPIOB, &gpio_init_struct);

    i2c_init(I2C1, I2C_FSMODE_DUTY_2_1, 400000);
    i2c_own_address1_set(I2C1, I2C_ADDRESS_MODE_7BIT, 0x0);
    i2c_ack_enable(I2C1, TRUE);
    i2c_clock_stretch_enable(I2C1, TRUE);
    i2c_general_call_enable(I2C1, FALSE);

    i2c_enable(I2C1, TRUE);

    /* add user code begin i2c1_init 2 */

    /* add user code end i2c1_init 2 */
}

/**
 * @brief  init usart2 function
 * @param  none
 * @retval none
 */
void wk_usart2_init(void)
{
    /* add user code begin usart2_init 0 */

    /* add user code end usart2_init 0 */

    gpio_init_type gpio_init_struct;
    gpio_default_para_init(&gpio_init_struct);

    /* add user code begin usart2_init 1 */

    /* add user code end usart2_init 1 */

    /* configure the TX pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode           = GPIO_MODE_MUX;
    gpio_init_struct.gpio_pins           = GPIO_PINS_2;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    /* configure the RX pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_MODERATE;
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;
    gpio_init_struct.gpio_pins           = GPIO_PINS_3;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    /* configure param */
    usart_init(USART2, 115200, USART_DATA_8BITS, USART_STOP_1_BIT);
    usart_transmitter_enable(USART2, TRUE);
    usart_receiver_enable(USART2, TRUE);
    usart_parity_selection_config(USART2, USART_PARITY_NONE);

    usart_hardware_flow_control_set(USART2, USART_HARDWARE_FLOW_NONE);

    usart_enable(USART2, TRUE);

    /* add user code begin usart2_init 2 */

    /* add user code end usart2_init 2 */
}

/**
 * @brief  init tmr1 function.
 * @param  none
 * @retval none
 */
void wk_tmr1_init(void)
{
    /* add user code begin tmr1_init 0 */

    /* add user code end tmr1_init 0 */

    /* add user code begin tmr1_init 1 */

    /* add user code end tmr1_init 1 */

    /* configure counter settings */
    tmr_base_init(TMR1, 1439, 499);
    tmr_cnt_dir_set(TMR1, TMR_COUNT_UP);
    tmr_clock_source_div_set(TMR1, TMR_CLOCK_DIV1);
    tmr_repetition_counter_set(TMR1, 0);
    tmr_period_buffer_enable(TMR1, FALSE);

    /* configure primary mode settings */
    tmr_sub_sync_mode_set(TMR1, FALSE);
    tmr_primary_mode_select(TMR1, TMR_PRIMARY_SEL_RESET);

    tmr_counter_enable(TMR1, TRUE);

    /**
     * Users need to configure TMR1 interrupt functions according to the actual application.
     * 1. Call the below function to enable the corresponding TMR1 interrupt.
     *     --tmr_interrupt_enable(...)
     * 2. Add the user's interrupt handler code into the below function in the at32f415_int.c file.
     *     --void TMR1_OVF_TMR10_IRQHandler(void)
     */

    /* add user code begin tmr1_init 2 */
    tmr_interrupt_enable(TMR1, TMR_OVF_INT, TRUE);
    // nvic_irq_enable(TMR1_OVF_TMR10_IRQn, 0, 0);
    /* add user code end tmr1_init 2 */
}

/**
 * @brief  init usb_otgfs1 function
 * @param  none
 * @retval none
 */
void wk_usb_otgfs1_init(void)
{
    /* add user code begin usb_otgfs1_init 0 */

    /* add user code end usb_otgfs1_init 0 */
    gpio_init_type gpio_init_struct;
    gpio_default_para_init(&gpio_init_struct);

    /* add user code begin usb_otgfs1_init 1 */

    /* add user code end usb_otgfs1_init 1 */

    /* configure the VBUS pin */
    gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
    gpio_init_struct.gpio_out_type       = GPIO_OUTPUT_PUSH_PULL;
    gpio_init_struct.gpio_mode           = GPIO_MODE_INPUT;
    gpio_init_struct.gpio_pins           = GPIO_PINS_9;
    gpio_init_struct.gpio_pull           = GPIO_PULL_NONE;
    gpio_init(GPIOA, &gpio_init_struct);

    crm_usb_clock_source_select(CRM_USB_CLOCK_SOURCE_PLL);

    crm_usb_clock_div_set(CRM_USB_DIV_3);

    /* add user code begin usb_otgfs1_init 2 */
    nvic_irq_enable(OTG_IRQ, 0, 0);

    /* init usb */
    usbd_init(&otg_core_struct,
              USB_FULL_SPEED_CORE_ID,
              USB_ID,
              &cdc_class_handler,
              &cdc_desc_handler);
    /* add user code end usb_otgfs1_init 2 */
}

/* add user code begin 1 */

#define PRINT_UART USART2

#if defined(__GNUC__) && !defined(__clang__)
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

/**
 * @brief  retargets the c library printf function to the usart.
 * @param  none
 * @retval none
 */
PUTCHAR_PROTOTYPE
{
    while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET)
        ;
    usart_data_transmit(PRINT_UART, (uint16_t)ch);
    while (usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET)
        ;
    return ch;
}

#if (defined(__GNUC__) && !defined(__clang__)) || (defined(__ICCARM__))
#if defined(__GNUC__) && !defined(__clang__)
int _write(int fd, char *pbuffer, int size)
#elif defined(__ICCARM__)
#pragma module_name = "?__write"
int __write(int fd, char *pbuffer, int size)
#endif
{
    for (int i = 0; i < size; i++) {
        while (usart_flag_get(PRINT_UART, USART_TDBE_FLAG) == RESET)
            ;
        usart_data_transmit(PRINT_UART, (uint16_t)(*pbuffer++));
        while (usart_flag_get(PRINT_UART, USART_TDC_FLAG) == RESET)
            ;
    }

    return size;
}
#endif

/**
 * @brief  this function handles otgfs interrupt.
 * @param  none
 * @retval none
 */
void OTG_IRQ_HANDLER(void)
{
    usbd_irq_handler(&otg_core_struct);
}

/**
 * @brief  usb delay millisecond function.
 * @param  ms: number of millisecond delay
 * @retval none
 */
void usb_delay_ms(uint32_t ms)
{
    /* user can define self delay function */
    delay_ms(ms);
}

/**
 * @brief  usb delay microsecond function.
 * @param  us: number of microsecond delay
 * @retval none
 */
void usb_delay_us(uint32_t us)
{
    delay_us(us);
}

/**
 * @brief  initialize delay function
 * @param  none
 * @retval none
 */
void delay_init()
{
    /* configure systick */
    systick_clock_source_config(SYSTICK_CLOCK_SOURCE_AHBCLK_NODIV);
    fac_us = system_core_clock / (1000000U);
    fac_ms = fac_us * (1000U);
}

/**
 * @brief  inserts a delay time.
 * @param  nus: specifies the delay time length, in microsecond.
 * @retval none
 */
void delay_us(uint32_t nus)
{
    uint32_t temp = 0;
    SysTick->LOAD = (uint32_t)(nus * fac_us);
    SysTick->VAL  = 0x00;
    SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
    do {
        temp = SysTick->CTRL;
    } while ((temp & 0x01) && !(temp & (1 << 16)));

    SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
    SysTick->VAL = 0x00;
}

/**
 * @brief  inserts a delay time.
 * @param  nms: specifies the delay time length, in milliseconds.
 * @retval none
 */
void delay_ms(uint16_t nms)
{
    uint32_t temp = 0;
    while (nms) {
        if (nms > STEP_DELAY_MS) {
            SysTick->LOAD = (uint32_t)(STEP_DELAY_MS * fac_ms);
            nms -= STEP_DELAY_MS;
        } else {
            SysTick->LOAD = (uint32_t)(nms * fac_ms);
            nms           = 0;
        }
        SysTick->VAL = 0x00;
        SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
        do {
            temp = SysTick->CTRL;
        } while ((temp & 0x01) && !(temp & (1 << 16)));

        SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
        SysTick->VAL = 0x00;
    }
}

/**
 * @brief  inserts a delay time.
 * @param  sec: specifies the delay time, in seconds.
 * @retval none
 */
void delay_sec(uint16_t sec)
{
    uint16_t index;
    for (index = 0; index < sec; index++) {
        delay_ms(500);
        delay_ms(500);
    }
}
/* add user code end 1 */
